package com.mic.gae.resource;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;

import com.google.appengine.api.users.UserService;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.mic.gae.dto.BuildDTO;
import com.mic.gae.dto.BuildsDTO;
import com.mic.gae.dto.ConsoleContentDTO;
import com.mic.gae.dto.ConsoleDTO;
import com.mic.gae.dto.ProjectDTO;
import com.mic.gae.dto.ProjectsDTO;
import com.mic.gae.dto.ServerDTO;
import com.mic.gae.resource.exception.UserNotLoggedInException;
import com.mic.gae.service.ContiniousIntegrationService;
import com.mic.gae.service.impl.HudsonContiniousIntegrationModule;

@Path("ci")
public class ContiniousIntegrationResource {

	private ContiniousIntegrationService continiousIntegrationService;
	private UserService userService;

	/**
	 * 
	 */
	public ContiniousIntegrationResource() {
		Injector injector = Guice.createInjector(new HudsonContiniousIntegrationModule());
		this.continiousIntegrationService = injector.getInstance(ContiniousIntegrationService.class);
		this.userService = injector.getInstance(UserService.class);
	}

	/**
	 * 
	 * @param urlToContinue
	 * @return
	 */
	@GET
	@Path("loginurl")
	@Produces("application/json")
	public String getLoginUrl(@QueryParam("continue") String urlToContinue) {
		return this.userService.createLoginURL(urlToContinue);
	}

	/**
	 * 
	 * @param urlToContinue
	 * @return
	 */
	@GET
	@Path("logouturl")
	@Produces("application/json")
	public String getLogoutUrl(@QueryParam("continue") String urlToContinue) {
		return this.userService.createLogoutURL(urlToContinue);
	}

	/**
	 * 
	 * @param serverDTO
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 */
	@POST
	@Path("server")
	@Produces("application/json")
	@Consumes("application/json")
	public ServerDTO addServer(ServerDTO serverDTO, @Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException {
		serverDTO.setIdentity(this.validateLogin(httpServletRequest.getRequestURI()));

		ServerDTO server = this.continiousIntegrationService.addServer(serverDTO);
		server.setProjectsUrl(new StringBuilder(httpServletRequest.getRequestURI()).append("projects/").toString());
		return server;
	}

	/**
	 * 
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 */
	@GET
	@Path("servers")
	@Produces("application/json")
	public List<ServerDTO> getServers(@Context HttpServletRequest httpServletRequest) throws UserNotLoggedInException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		List<ServerDTO> servers = this.continiousIntegrationService.getServers(identity);
		for (ServerDTO server : servers) {
			server.setProjectsUrl(new StringBuilder(httpServletRequest.getRequestURI()).append("projects/").toString());
		}
		return servers;
	}

	/**
	 * 
	 * @param serverId
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 */
	@GET
	@Path("servers/{serverId}")
	@Produces("application/json")
	public ServerDTO getServer(@PathParam("serverId") Long serverId, @Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		ServerDTO server = this.continiousIntegrationService.getServer(identity, serverId);
		server.setProjectsUrl(new StringBuilder(httpServletRequest.getRequestURI()).append("projects/").toString());

		return server;
	}

	/**
	 * 
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@GET
	@Path("servers/all")
	@Produces("application/json")
	public List<ServerDTO> getServerAll(@Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());

		List<ServerDTO> result = new ArrayList<ServerDTO>();

		List<ServerDTO> servers = this.continiousIntegrationService.getServers(identity);
		for (ServerDTO server : servers) {
			server = this.continiousIntegrationService.getServer(identity, server.getKey());
			ProjectsDTO projectsDTO = this.continiousIntegrationService.getProjects(identity, server.getKey());
			server.setProjectsDTO(projectsDTO);
			for (ProjectDTO projectDTO : projectsDTO.getProjects()) {
				BuildsDTO projectBuilds = this.continiousIntegrationService.getProjectBuilds(identity, server.getKey(),
				        projectDTO.getName());
				projectDTO.setBuilds(projectBuilds);
			}
			result.add(server);
		}
		return result;
	}

	/**
	 * 
	 * @param serverId
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 */
	@DELETE
	@Path("servers/{serverId}")
	@Produces("application/json")
	public Long deleteServer(@PathParam("serverId") Long serverId, @Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		return this.continiousIntegrationService.deleteServer(identity, serverId);
	}

	/**
	 * 
	 * @param serverId
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@GET
	@Path("servers/{serverId}/projects")
	@Produces("application/json")
	public ProjectsDTO getProjects(@PathParam("serverId") Long serverId, @Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		ProjectsDTO projectsDTO = this.continiousIntegrationService.getProjects(identity, serverId);
		List<ProjectDTO> projects = projectsDTO.getProjects();
		for (ProjectDTO project : projects) {
			project.setBuildsUrl(new StringBuilder(httpServletRequest.getRequestURI()).append(project.getName())
			        .append("/").append("builds/").toString());
		}
		return projectsDTO;
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@GET
	@Path("servers/{serverId}/projects/{projectName}")
	@Produces("application/json")
	public ProjectDTO getProject(@PathParam("serverId") Long serverId, @PathParam("projectName") String projectName,
	        @Context HttpServletRequest httpServletRequest) throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		ProjectDTO project = this.continiousIntegrationService.getProject(identity, serverId, projectName);
		project.setBuildsUrl(new StringBuilder(httpServletRequest.getRequestURI()).append(project.getName())
		        .append("/").append("builds/").toString());
		return project;
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@GET
	@Path("servers/{serverId}/projects/{projectName}/builds")
	@Produces("application/json")
	public BuildsDTO getProjectBuilds(@PathParam("serverId") Long serverId,
	        @PathParam("projectName") String projectName, @Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		BuildsDTO projectBuildsDTO = this.continiousIntegrationService
		        .getProjectBuilds(identity, serverId, projectName);
		List<BuildDTO> builds = projectBuildsDTO.getBuilds();
		for (BuildDTO projectBuild : builds) {
			projectBuild.setConsoleUrl(new StringBuilder(httpServletRequest.getRequestURI()).append("/")
			        .append(projectBuild.getNumber()).append("/console/").toString());
		}

		return projectBuildsDTO;
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param buildNumber
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@GET
	@Path("servers/{serverId}/projects/{projectName}/builds/{buildNumber}")
	@Produces("application/json")
	public BuildDTO getProjectBuild(@PathParam("serverId") Long serverId, @PathParam("projectName") String projectName,
	        @PathParam("buildNumber") Long buildNumber, @Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		BuildDTO projectBuild = this.continiousIntegrationService.getProjectBuild(identity, serverId, projectName,
		        buildNumber);
		projectBuild.setConsoleUrl(new StringBuilder(httpServletRequest.getRequestURI()).append("console/").toString());
		return projectBuild;
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param buildNumber
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@GET
	@Path("servers/{serverId}/projects/{projectName}/builds/{buildNumber}/console")
	@Produces("application/json")
	public ConsoleDTO getProjectConsole(@PathParam("serverId") Long serverId,
	        @PathParam("projectName") String projectName, @PathParam("buildNumber") Long buildNumber,
	        @Context HttpServletRequest httpServletRequest) throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		ConsoleDTO projectConsole = this.continiousIntegrationService.getProjectConsole(identity, serverId,
		        projectName, buildNumber);
		projectConsole.setContentUrl(new StringBuilder(httpServletRequest.getRequestURI()).append("content/")
		        .toString());

		return projectConsole;
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param buildNumber
	 * @param offset
	 * @param length
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@GET
	@Path("servers/{serverId}/projects/{projectName}/builds/{buildNumber}/console/content")
	@Produces("application/json")
	public ConsoleContentDTO getProjectConsoleContent(@PathParam("serverId") Long serverId,
	        @PathParam("projectName") String projectName, @PathParam("buildNumber") Long buildNumber,
	        @DefaultValue("0") @QueryParam("offset") Long offset, @QueryParam("length") Long length,
	        @Context HttpServletRequest httpServletRequest) throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		return this.continiousIntegrationService.getProjectConsoleContent(identity, serverId, projectName, buildNumber,
		        offset, length);
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param buildParameter
	 * @param httpServletRequest
	 * @return
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@PUT
	@Path("servers/{serverId}/projects/{projectName}/build")
	@Consumes("application/json")
	@Produces("application/json")
	public Map<String, String> startProjectBuild(@PathParam("serverId") Long serverId,
	        @PathParam("projectName") String projectName, Map<String, String> buildParameter,
	        @Context HttpServletRequest httpServletRequest) throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		return this.continiousIntegrationService.startProjectBuild(identity, serverId, projectName, buildParameter);
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param buildNumber
	 * @param httpServletRequest
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@PUT
	@Path("servers/{serverId}/projects/{projectName}/builds/{buildNumber}/stop")
	public void stopProjectBuild(@PathParam("serverId") Long serverId, @PathParam("projectName") String projectName,
	        @PathParam("buildNumber") Long buildNumber, @Context HttpServletRequest httpServletRequest)
	        throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		this.continiousIntegrationService.stopProjectBuild(identity, serverId, projectName, buildNumber);
	}

	/**
	 * 
	 * @param serverId
	 * @param projectName
	 * @param httpServletRequest
	 * @throws UserNotLoggedInException
	 * @throws IOException
	 */
	@DELETE
	@Path("servers/{serverId}/projects/{projectName}")
	public void deleteProject(@PathParam("serverId") Long serverId, @PathParam("projectName") String projectName,
	        @Context HttpServletRequest httpServletRequest) throws UserNotLoggedInException, IOException {
		String identity = this.validateLogin(httpServletRequest.getRequestURI());
		this.continiousIntegrationService.deleteProject(identity, serverId, projectName);
	}

	/**
	 * 
	 * @param urlToContinue
	 * @return
	 * @throws UserNotLoggedInException
	 */
	private String validateLogin(String urlToContinue) throws UserNotLoggedInException {
		if (this.userService.isUserLoggedIn() == false) {
			throw new UserNotLoggedInException(this.getLoginUrl(urlToContinue));
		}
		return this.userService.getCurrentUser().getFederatedIdentity();
	}
}
